package ms.maplestory.boot.loaders;

import lombok.extern.slf4j.Slf4j;
import ms.maplestory.boot.ServerConstants;
import ms.maplestory.boot.world.field.objects.mob.Mob;
import ms.maplestory.boot.world.field.objects.mob.MobStat;
import ms.maplestory.boot.world.field.objects.mob.MobTemporaryStat;
import ms.maplestory.boot.world.field.objects.mob.skill.MobSkill;
import ms.maplestory.boot.util.Util;
import ms.maplestory.boot.util.XMLApi;
import ms.maplestory.boot.util.container.Tuple;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import java.io.*;
import java.util.*;

import static ms.maplestory.boot.loaders.MainLoader.INFO_OUT;

@Slf4j
public class MobData {

    private static Map<Integer, Mob> mobs = new HashMap<>();

    public static void generateDatFiles() {
        log.info("Started generating mob data.");
        long start = System.currentTimeMillis();
        loadMobsFromWz();
        QuestData.linkMobData();
        saveMobsToDat(ServerConstants.DAT_DIR + "/mobs");
        log.info(String.format("Completed generating mob data in %dms.", System.currentTimeMillis() - start));
    }

    public static void loadMobsFromWz() {
        String wzDir = ServerConstants.WZ_DIR + "/Mob.wz";
        File dir = new File(wzDir);
        File[] files1 = dir.listFiles();
        List<File> files = new ArrayList<>();
        files.addAll(Arrays.asList(files1));
        for (File file : files) {
            if (file.isDirectory()) {
                continue;
            }
            Document doc = XMLApi.getRoot(file);
            Node node = XMLApi.getAllChildren(doc).get(0);
            if (node == null) {
                continue;
            }
            //加载怪物死亡延迟
            String[] deathNodes = {"die1", "die2", "dieF"};
            long revive = 0;
            for (String s : deathNodes) {
                Node deathNode = XMLApi.getFirstChildByNameBF(node, s);
                if (deathNode == null) {
                    continue;
                }
                for (Node n : XMLApi.getAllChildren(deathNode)) {
                    for (Node n2 : XMLApi.getAllChildren(n)) {
                        String name = XMLApi.getNamedAttribute(n2, "name");
                        if (!name.equalsIgnoreCase("delay")) {
                            continue;
                        }
                        String value = XMLApi.getNamedAttribute(n2, "value");
                        revive += Integer.parseInt(value);
                    }
                }
            }
            int id = Integer.parseInt(XMLApi.getNamedAttribute(node, "name").replace(".img", ""));
            Node infoNode = XMLApi.getFirstChildByNameBF(node, "info");
            Mob mob = new Mob(id);
            MobStat mobStat = mob.getMobStat();
            MobTemporaryStat mts = mob.getTemporaryStat();
            for (Node n : XMLApi.getAllChildren(infoNode)) {
                String name = XMLApi.getNamedAttribute(n, "name");
                String value = XMLApi.getNamedAttribute(n, "value");
                switch (name) {
                    case "level":
                        mobStat.setLevel(Integer.parseInt(value));
                        break;
                    case "firstAttack":
                    case "firstattack":
                        mob.setFirstAttack((int) Double.parseDouble(value));
                        break;
                    case "bodyAttack":
                    case "bodyattack":
                        //Mask bodyOpt = new Mask();
                        //bodyOpt.nOption = Integer.parseInt(value);
                        //mts.addStatMask(BodyAttack, bodyOpt);
                        break;
                    case "maxHP":
                        mobStat.setMaxHP(Integer.parseInt(value));
                        break;
                    case "maxMP":
                        mobStat.setMaxMP(Integer.parseInt(value));
                        break;
                    case "PADamage":
                        mobStat.setPADamage(Integer.parseInt(value));
                        break;
                    case "PDDamage":
                        mobStat.setPDDamage(Integer.parseInt(value));
                        break;
                    case "PDRate":
                        mobStat.setPDRate(Integer.parseInt(value));
                        break;
                    case "MADamage":
                        mobStat.setMADamage(Integer.parseInt(value));
                        break;
                    case "MDDamage":
                        mobStat.setMDDamage(Integer.parseInt(value));
                        break;
                    case "MDRate":
                        mobStat.setMDRate(Integer.parseInt(value));
                        break;
                    case "acc":
                        mobStat.setAcc(Integer.parseInt(value));
                        break;
                    case "eva":
                        mobStat.setEva(Integer.parseInt(value));
                        break;
                    case "pushed":
                        mobStat.setPushed(Integer.parseInt(value));
                        break;
                    case "exp":
                        mobStat.setExp(Long.parseLong(value));
                        break;
                    case "summonType":
                        mob.setSummonType(Integer.parseInt(value));
                        break;
                    case "category":
                        mob.setCategory(Integer.parseInt(value));
                        break;
                    case "mobType":
                        mob.setMobType(value);
                        break;
                    case "link":
                        mob.setLink(Integer.parseInt(value));
                        break;
                    case "speed":
                    case "Speed":
                        mobStat.setSpeed(Integer.parseInt(value));
                        break;
                    case "fs":
                        mob.setFs(Double.parseDouble(value));
                        break;
                    case "elemAttr":
                        mob.setElemAttr(value);
                        break;
                    case "hpTagColor":
                        mob.setHpTagColor(Integer.parseInt(value));
                        break;
                    case "hpTagBgcolor":
                        mob.setHpTagBgColor(Integer.parseInt(value));
                        break;
                    case "HPgaugeHide":
                        mob.setHPGaugeHide(Integer.parseInt(value) == 1);
                        break;
                    case "boss":
                        mob.setBoss(Integer.parseInt(value) == 1);
                        break;
                    case "undead":
                    case "Undead":
                        mob.setUndead(Integer.parseInt(value) == 1);
                        break;
                    case "noregen":
                        mob.setNoRegen(Integer.parseInt(value) == 1);
                        break;
                    case "invincible":
                        mob.setInvincible(Integer.parseInt(value) == 1);
                        break;
                    case "hideName":
                    case "hidename":
                        mob.setHideName(Integer.parseInt(value) == 1);
                        break;
                    case "hideHP":
                        mob.setHideHP(Integer.parseInt(value) == 1);
                        break;
                    case "noFlip":
                        mob.setNoFlip(Integer.parseInt(value) == 1);
                        break;
                    case "publicReward":
                        mob.setPublicReward(Integer.parseInt(value) == 1);
                        break;
                    case "ignoreFieldOut":
                        mob.setIgnoreFieldOut(Integer.parseInt(value) == 1);
                        break;
                    case "noDoom":
                        mob.setNoDoom(Integer.parseInt(value) == 1);
                        break;
                    case "knockback":
                        mob.setKnockBack(Integer.parseInt(value) == 1);
                        break;
                    case "removeQuest":
                        mob.setRemoveQuest(Integer.parseInt(value) == 1);
                        break;
                    case "rareItemDropLevel":
                        mob.setRareItemDropLevel(Integer.parseInt(value));
                        break;
                    case "hpRecovery":
                        mob.setHpRecovery(Integer.parseInt(value));
                        break;
                    case "mpRecovery":
                        mob.setMpRecovery(Integer.parseInt(value));
                        break;
                    case "mbookID":
                        mob.setMBookID(Integer.parseInt(value));
                        break;
                    case "chaseSpeed":
                        mob.setChaseSpeed(Integer.parseInt(value));
                        break;
                    case "explosiveReward":
                        mob.setExplosiveReward(Integer.parseInt(value));
                        break;
                    case "flyspeed":
                    case "flySpeed":
                    case "FlySpeed":
                        mob.setFlySpeed(Integer.parseInt(value));
                        break;
                    case "fixedDamage":
                        mob.setFixedDamage(Integer.parseInt(value));
                        break;
                    case "removeAfter":
                        mob.setRemoveAfter(Integer.parseInt(value));
                        break;
                    case "point":
                        mob.setPoint(Integer.parseInt(value));
                        break;
                    case "coolDamage":
                        mob.setCoolDamage(Integer.parseInt(value));
                        break;
                    case "coolDamageProb":
                        mob.setCoolDamageProb(Integer.parseInt(value));
                        break;
                    case "ban":
                        mob.setBan(true);
                        for (Node banNode : XMLApi.getAllChildren(n)) {
                            String banNodeName = XMLApi.getNamedAttribute(banNode, "name");
                            String banNodeValue = XMLApi.getNamedAttribute(banNode, "value");
                            switch (banNodeName) {
                                case "banType":
                                    mob.setBanType(Integer.parseInt(banNodeValue));
                                    break;
                                case "banMsgType":
                                    mob.setBanMsgType(Integer.parseInt(banNodeValue));
                                    break;
                                case "banMsg":
                                    mob.setBanMsg(banNodeValue);
                                    break;
                                case "banMap":
                                    for (Node banMaps : XMLApi.getAllChildren(banNode)) {
                                        int banFieldID = 0;
                                        String banPortal = "";
                                        for (Node banMap : XMLApi.getAllChildren(banMaps)) {
                                            String banMapName = XMLApi.getNamedAttribute(banMap, "name");
                                            String banMapValue = XMLApi.getNamedAttribute(banMap, "value");
                                            switch (banMapName) {
                                                case "field":
                                                    banFieldID = Integer.parseInt(banMapValue);
                                                    break;
                                                case "portal":
                                                    banPortal = banMapValue;
                                                    break;
                                                default:
                                                    if (INFO_OUT)
                                                    log.warn(String.format("Unknown ban map node %s with value %s", banMapName, banMapValue));
                                                    break;
                                            }
                                            if (banFieldID != 0) {
                                                mob.addBanMap(banFieldID, banPortal);
                                            }
                                        }
                                    }
                                    break;
                            }
                        }
                        break;
                    case "revive":
                        mob.setRevive(revive);
                        for (Node reviveNode : XMLApi.getAllChildren(n)) {
                            mob.addRevive(Integer.parseInt((XMLApi.getNamedAttribute(reviveNode, "value"))));
                        }
                        break;
                    case "skill":
                        for (Node skillIDNode : XMLApi.getAllChildren(n)) {
                            if (!Util.isNumber(XMLApi.getNamedAttribute(skillIDNode, "name"))) {
                                continue;
                            }
                            MobSkill mobSkill = new MobSkill();
                            mobSkill.setId(Integer.parseInt(XMLApi.getNamedAttribute(skillIDNode, "name")));
                            for (Node skillInfoNode : XMLApi.getAllChildren(skillIDNode)) {
                                String skillNodeName = XMLApi.getNamedAttribute(skillInfoNode, "name");
                                String skillNodeValue = XMLApi.getNamedAttribute(skillInfoNode, "value");
                                switch (skillNodeName) {
                                    case "skill":
                                        mobSkill.setSkill(Integer.parseInt(skillNodeValue));
                                        break;
                                    case "action":
                                        mobSkill.setAction(Integer.parseInt(skillNodeValue));
                                        break;
                                    case "level":
                                        mobSkill.setLevel(Integer.parseInt(skillNodeValue));
                                        break;
                                    case "effectAfter":
                                        if (!skillNodeValue.equals("")) {
                                            mobSkill.setEffectAfter(Integer.parseInt(skillNodeValue));
                                        }
                                        break;
                                    case "skillAfter":
                                        mobSkill.setSkillAfter(Integer.parseInt(skillNodeValue));
                                        break;
                                    default:
                                        if (INFO_OUT)
                                        log.warn(String.format("Unknown skill node %s with value %s", skillNodeName, skillNodeValue));
                                }
                            }
                            mob.addSkill(mobSkill);
                        }
                        break;
                    case "selfDestruction":
                        // TODO Maybe more info?
                        mob.setSelfDestruction(true);
                        break;
                    case "escort":
                        mob.setEscort(Integer.parseInt(value) != 0);
                        break;
                    case "speak":
                    case "thumbnail":
                    case "default":
                    case "defaultHP":
                    case "defaultMP":
                    case "passive":
                    case "firstAttackRange":
                    case "nonLevelCheckEVA":
                    case "nonLevelCheckACC":
                    case "changeImg":
                    case "showNotRemoteDam":
                    case "buff":
                    case "damagedBySelectedMob":
                    case "damagedByMob":
                    case "getCP":
                    case "loseItem":
                    case "0":
                    case "onlyNormalAttack":
                    case "notConsiderFieldSet":
                    case "overSpeed":
                    case "ignoreMovable":
                    case "jsonLoad":
                    case "fixedBodyAttackDamageR":
                    case "adjustLayerZ":
                    case "damagedBySelectedSkill":
                    case "option_damagedByMob":
                    case "bodyKnockBack":
                    case "straightMoveDir":
                    case "onlyHittedByCommonAttack":
                    case "invincibleAttack":
                    case "noChase":
                    case "notAttack":
                    case "alwaysInAffectedRect":
                    case "firstShowHPTag":
                    case "pointFPSMode":
                    case "11":
                    case "prevLinkMob":
                    case "option_skeleton":
                    case "lifePoint":
                    case "defenseMob":
                    case "forceChaseEscort":
                    case "damageModification":
                    case "randomFlyingBoss":
                    case "randomFlyingMob":
                    case "stalking":
                    case "minimap":
                    case "removeOnMiss":
                    case "fieldEffect":
                    case "onceReward":
                    case "onMobDeadQR":
                    case "peddlerMob":
                    case "peddlerDamR":
                    case "rewardSprinkle":
                    case "rewardSprinkleCount":
                    case "rewardSprinkleSpeed":
                    case "ignorMoveImpact":
                    case "dropItemPeriod":
                    case "hideMove":
                    case "atom":
                    case "smartPhase":
                    case "trans":
                    case "chaseEffect":
                    case "dualGauge":
                    case "noReturnByDead":
                    case "AngerGauge":
                    case "ChargeCount":
                    case "upperMostLayer":
                    case "cannotEvade":
                    case "phase":
                    case "doNotRemove":
                    case "healOnDestroy":
                    case "debuffobj":
                    case "obtacle":
                    case "mobZone":
                    case "weapon":
                    case "forcedFlip":
                    case "buffStack":
                    case "001":
                    case "002":
                    case "003":
                    case "004":
                    case "005":
                    case "006":
                    case "007":
                    case "008":
                    case "009":
                    case "010":
                    case "011":
                    case "onlySelectedSkill":
                    case "finalAdjustedDamageRate":
                    case "battlePvP":
                    case "mobJobCategory":
                    case "considerUserCount":
                    case "randomMob":
                    case "dieHeight":
                    case "dieHeightTime":
                    case "notChase":
                    case "fixedStat":
                    case "allyMob":
                    case "linkMob":
                    case "skelAniMixRate":
                    case "mobZoneObjID":
                    case "mobZoneObjType":
                    case "holdRange":
                    case "targetChaseTime":
                    case "copyCharacter":
                    case "disable":
                    case "underObject":
                    case "1582":
                    case "peddlerCount":
                    case "bodyAttackInfo":
                    case "mobZoneType":
                    case "largeDamageRecord":
                    case "considerUserCounter":
                    case "damageByObtacleAtom":
                    case "info":
                    case "cantPassByTeleport":
                    case "250000":
                    case "forward_direction":
                        break;
                    default:
                        if (INFO_OUT)
                            log.warn(String.format("Unkown property %s with value %s.", name, value));
                }
                mobs.put(mob.getId(), mob);
            }
        }
    }

    private static void saveMobsToDat(String dir) {
        Util.makeDirIfAbsent(dir);
        for (Mob mob : mobs.values()) {
            File file = new File(dir + "/" + mob.getId() + ".dat");
            try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(file))) {
                MobStat fms = mob.getMobStat();
                MobTemporaryStat mts = mob.getTemporaryStat();
                dataOutputStream.writeInt(mob.getId());
                dataOutputStream.writeInt(fms.getLevel());
                dataOutputStream.writeInt(mob.getFirstAttack());
                //dataOutputStream.writeInt(mts.getNewOptionsByMobStat(BodyAttack) != null ? mts.getNewOptionsByMobStat(BodyAttack).nOption : 0);
                dataOutputStream.writeInt(0);
                dataOutputStream.writeLong(fms.getMaxHP());
                dataOutputStream.writeLong(fms.getMaxMP());
                dataOutputStream.writeInt(fms.getPADamage());
                dataOutputStream.writeInt(fms.getPDRate());
                dataOutputStream.writeInt(fms.getMADamage());
                dataOutputStream.writeInt(fms.getMDRate());
                dataOutputStream.writeInt(fms.getAcc());
                dataOutputStream.writeInt(fms.getEva());
                dataOutputStream.writeInt(fms.getPushed());
                dataOutputStream.writeLong(fms.getExp());
                dataOutputStream.writeInt(mob.getSummonType());
                dataOutputStream.writeInt(mob.getCategory());
                dataOutputStream.writeUTF(mob.getMobType());
                dataOutputStream.writeInt(mob.getLink());
                dataOutputStream.writeInt(fms.getSpeed());
                dataOutputStream.writeDouble(mob.getFs());
                dataOutputStream.writeUTF(mob.getElemAttr());
                dataOutputStream.writeInt(mob.getHpTagColor());
                dataOutputStream.writeInt(mob.getHpTagBgColor());
                dataOutputStream.writeLong(mob.getRevive());
                dataOutputStream.writeBoolean(mob.isHPGaugeHide());
                dataOutputStream.writeBoolean(mob.isBoss());
                dataOutputStream.writeBoolean(mob.isUndead());
                dataOutputStream.writeBoolean(mob.isNoRegen());
                dataOutputStream.writeBoolean(mob.isInvincible());
                dataOutputStream.writeBoolean(mob.isHideName());
                dataOutputStream.writeBoolean(mob.isHideHP());
                dataOutputStream.writeBoolean(mob.isNoFlip());
                dataOutputStream.writeBoolean(mob.isPublicReward());
                dataOutputStream.writeBoolean(mob.isIgnoreFieldOut());
                dataOutputStream.writeBoolean(mob.isNoDoom());
                dataOutputStream.writeBoolean(mob.isRemoveQuest());
                dataOutputStream.writeInt(mob.getRareItemDropLevel());
                dataOutputStream.writeInt(mob.getHpRecovery());
                dataOutputStream.writeInt(mob.getMpRecovery());
                dataOutputStream.writeInt(mob.getMBookID());
                dataOutputStream.writeInt(mob.getChaseSpeed());
                dataOutputStream.writeInt(mob.getExplosiveReward());
                dataOutputStream.writeInt(mob.getFlySpeed());
                dataOutputStream.writeInt(mob.getFixedDamage());
                dataOutputStream.writeInt(mob.getRemoveAfter());
                dataOutputStream.writeInt(mob.getPoint());
                dataOutputStream.writeInt(mob.getCoolDamage());
                dataOutputStream.writeInt(mob.getCoolDamageProb());
                dataOutputStream.writeBoolean(mob.isBan());
                if (mob.isBan()) {
                    dataOutputStream.writeInt(mob.getBanType());
                    dataOutputStream.writeInt(mob.getBanMsgType());
                    dataOutputStream.writeUTF(mob.getBanMsg());
                    dataOutputStream.writeShort(mob.getBanMap().size());
                    for (Tuple<Integer, String> banMap : mob.getBanMap()) {
                        dataOutputStream.writeInt(banMap.getLeft());
                        dataOutputStream.writeUTF(banMap.getRight());
                    }
                }
                dataOutputStream.writeShort(mob.getRevives().size());
                for (int i : mob.getRevives()) {
                    dataOutputStream.writeInt(i);
                }
                dataOutputStream.writeShort(mob.getSkills().size());
                List<MobSkill> all = mob.getSkills();
                for (MobSkill ms : all) {
                    dataOutputStream.writeInt(ms.getId());
                    dataOutputStream.writeInt(ms.getSkill());
                    dataOutputStream.writeInt(ms.getAction());
                    dataOutputStream.writeInt(ms.getLevel());
                    dataOutputStream.writeInt(ms.getEffectAfter());
                    dataOutputStream.writeInt(ms.getSkillAfter());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static Mob loadMobFromDat(int id) {
        File file = new File(ServerConstants.DAT_DIR + "/mobs/" + id + ".dat");
        if (!file.exists()) {
            return null;
        }
        Mob mob = null;
        try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file))) {
            mob = new Mob(dataInputStream.readInt());
            MobStat fms = mob.getMobStat();
            fms.setLevel(dataInputStream.readInt());
            mob.setFirstAttack(dataInputStream.readInt());
//            Option bodyOpt = new Option();
//            bodyOpt.nOption = dataInputStream.readInt();
            dataInputStream.readInt();
//            mts.addStatOptions(BodyAttack, bodyOpt);
            fms.setMaxHP(dataInputStream.readLong());
            fms.setMaxMP(dataInputStream.readLong());
            fms.setPADamage(dataInputStream.readInt());
            fms.setPDRate(dataInputStream.readInt());
            fms.setMADamage(dataInputStream.readInt());
            fms.setMDRate(dataInputStream.readInt());
            fms.setAcc(dataInputStream.readInt());
            fms.setEva(dataInputStream.readInt());
            fms.setPushed(dataInputStream.readInt());
            fms.setExp(dataInputStream.readLong());
            mob.setSummonType(dataInputStream.readInt());
            mob.setCategory(dataInputStream.readInt());
            mob.setMobType(dataInputStream.readUTF());
            mob.setLink(dataInputStream.readInt());
            fms.setSpeed(dataInputStream.readInt());
            mob.setFs(dataInputStream.readDouble());
            mob.setElemAttr(dataInputStream.readUTF());
            mob.setHpTagColor(dataInputStream.readInt());
            mob.setHpTagBgColor(dataInputStream.readInt());
            mob.setRevive(dataInputStream.readLong());
            mob.setHPGaugeHide(dataInputStream.readBoolean());
            mob.setBoss(dataInputStream.readBoolean());
            mob.setUndead(dataInputStream.readBoolean());
            mob.setNoRegen(dataInputStream.readBoolean());
            mob.setInvincible(dataInputStream.readBoolean());
            mob.setHideName(dataInputStream.readBoolean());
            mob.setHideHP(dataInputStream.readBoolean());
            mob.setNoFlip(dataInputStream.readBoolean());
            mob.setPublicReward(dataInputStream.readBoolean());
            mob.setIgnoreFieldOut(dataInputStream.readBoolean());
            mob.setNoDoom(dataInputStream.readBoolean());
            mob.setRemoveQuest(dataInputStream.readBoolean());
            mob.setRareItemDropLevel(dataInputStream.readInt());
            mob.setHpRecovery(dataInputStream.readInt());
            mob.setMpRecovery(dataInputStream.readInt());
            mob.setMBookID(dataInputStream.readInt());
            mob.setChaseSpeed(dataInputStream.readInt());
            mob.setExplosiveReward(dataInputStream.readInt());
            mob.setFlySpeed(dataInputStream.readInt());
            mob.setFixedDamage(dataInputStream.readInt());
            mob.setRemoveAfter(dataInputStream.readInt());
            mob.setPoint(dataInputStream.readInt());
            mob.setCoolDamage(dataInputStream.readInt());
            mob.setCoolDamageProb(dataInputStream.readInt());
            boolean banMap = dataInputStream.readBoolean();
            if (banMap) {
                mob.setBan(true);
                mob.setBanType(dataInputStream.readInt());
                mob.setBanMsgType(dataInputStream.readInt());
                mob.setBanMsg(dataInputStream.readUTF());
                short size = dataInputStream.readShort();
                for (int i = 0; i < size; i++) {
                    mob.addBanMap(dataInputStream.readInt(), dataInputStream.readUTF());
                }
            }
            short size = dataInputStream.readShort();
            for (int i = 0; i < size; i++) {
                mob.addQuest(dataInputStream.readInt());
            }
            size = dataInputStream.readShort();
            for (int i = 0; i < size; i++) {
                mob.addRevive(dataInputStream.readInt());
            }
            short skillSize = dataInputStream.readShort();
            for (int i = 0; i < skillSize; i++) {
                MobSkill ms = new MobSkill();
                ms.setId(dataInputStream.readInt());
                ms.setSkill(dataInputStream.readInt());
                ms.setAction(dataInputStream.readInt());
                ms.setLevel(dataInputStream.readInt());
                ms.setEffectAfter(dataInputStream.readInt());
                ms.setSkillAfter(dataInputStream.readInt());
                mob.addSkill(ms);
            }

//            mob.setAppearType((byte) -2); // new spawn
//            mob.setAfterAttack(-1);
//            mob.setCurrentAction(-1);
//            mob.setEliteGrade(-1);
//            mob.setMoveAction((byte) 5); // normal monster?
//            mob.setHp(fms.getMaxHP());
//            mob.setMaxHp(fms.getMaxHP());
//            mob.setMp(fms.getMaxMP());
//            mob.setMaxMp(fms.getMaxMP());
//            mob.setDrops(DropData.getDropInfoByID(mob.getTemplateId()).stream().filter(dropInfo -> !dropInfo.isReactorDrop()).collect(Collectors.toSet()));
//            mob.getDrops().add(new DropInfo(GameConstants.MAX_DROP_CHANCE,
//                    GameConstants.MIN_MONEY_MULT * mob.getForcedMobStat().getLevel(),
//                    GameConstants.MAX_MONEY_MULT * mob.getForcedMobStat().getLevel()
//            ));
//            for (DropInfo di : mob.getDrops()) {
//                di.generateNextDrop();
//            }
            addMob(mob);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mob;
    }

    public static Mob getMobById(int id) {
        Mob mob = mobs.get(id);
        if (mob == null) {
            mob = loadMobFromDat(id);
        }
        return mob;
    }

    public static void addMob(Mob mob) {
        mobs.put(mob.getId(), mob);
    }

    public static Mob getMobDeepCopyById(int id) {
        Mob from = getMobById(id);
        Mob copy = null;
        if (from != null) {
            copy = from.deepCopy();
        }
        return copy;
    }
}
